package de.cbf.cam.dsa.exchange.heldenrmi;

import helden.rmi.RmtServer;
import helden.rmi.wrapper.WrappedEigenschaften;
import helden.rmi.wrapper.WrappedGegenstand;
import helden.rmi.wrapper.WrappedHeld;
import helden.rmi.wrapper.WrappedSonderfertigkeit;
import helden.rmi.wrapper.WrappedSonderfertigkeiten;
import helden.rmi.wrapper.WrappedTalent;
import helden.rmi.wrapper.WrappedTalente;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;

import de.cbf.cam.dsa.exchange.exceptions.CharacterImportException;
import de.cbf.cam.dsa.exchange.heldenrmi.descriptions.CharacterDescription;
import de.cbf.cam.dsa.exchange.heldenrmi.preferences.PreferenceConstants;
import de.cbf.cam.dsa.exchange.heldenrmi.views.ImportRMIView;
import de.cbf.cam.dsa.model.Model;
import de.cbf.cam.dsa.model.ModelBase;
import de.cbf.cam.dsa.model.entities.OneAttribute;
import de.cbf.cam.dsa.model.entities.OneNPC;
import de.cbf.cam.dsa.model.entities.OneTalent;
import de.cbf.cam.dsa.model.entities.SF;
import de.cbf.cam.dsa.model.entities.WeaponTalent;
import de.cbf.cam.dsa.model.entities.items.Item;

/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends AbstractUIPlugin  implements IPartListener2  {

	// The plug-in ID
	public static final String PLUGIN_ID = "de.cbf.cam.dsa.exchange.heldenRMI";

	// The shared instance
	private static Activator plugin;

	private RmtServer server = null;
	
	private ImportRMIView view;
	
	private ImportFunctionality importFunctionality = new ImportFunctionality();
	private ReloadFunctionality reloadFunctionality = new ReloadFunctionality();
	
	/**
	 * The constructor
	 */
	public Activator() {
		//register as listener for view opening/closing
		getWorkbench().getActiveWorkbenchWindow().getActivePage().addPartListener(this);
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;		
	}

	/*
	 * (non-Javadoc)
	 * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}

	/**
	 * Returns the shared instance
	 *
	 * @return the shared instance
	 */
	public static Activator getDefault() {
		return plugin;
	}	
	@SuppressWarnings("unused")
	public void startRuntimeTest() throws IOException{
		
		File javaDirectory = new File("C:/Programme/Java/jre6/bin/java.exe");		
		String heldenPath = "helden.jar";
//		String heldenPath = "";
		String parameter  = "";//-rmi
		
		ProcessBuilder processBuilder = new ProcessBuilder("D:\\a.bat");
		processBuilder.directory(new File("D:/"));
		Map<String,String> environment = processBuilder.environment();
		
		
		Process process = processBuilder.start();
		try {
			process.waitFor();
			int test = process.exitValue();
		} catch (InterruptedException e) {			
		}
	}
		
	public List<CharacterDescription> getHelden() throws RemoteException{
		List<CharacterDescription> resultList = new ArrayList<CharacterDescription>(); 
		try {
			if(server == null){				
				server = connectToServer();
			}
			String[] heldenIds = server.getAllHeldenID();
			for (int i = 0; i < heldenIds.length; i++) {
				//held found					
				WrappedHeld held = server.getHeld(heldenIds[i]);
				
				CharacterDescription description = new CharacterDescription();
				description.setId(heldenIds[i]);			
				description.setName(held.getName());
				description.setRace(held.getRassenName());
				description.setCulture(held.getKulturName());
				description.setProfession(held.getProfessionName());
				description.setAp(held.getAbenteuerpunkte());
				description.setAvailAP(held.getVerfuegbareAbenteuerpunkte());
				resultList.add(description);
			}
		} catch (MalformedURLException e) {				
		} catch (NotBoundException e) {				
		}
		return resultList;
	}
	
	
	
	public OneNPC importCharacter(String heldenID) throws CharacterImportException{		
		try {
			if(server == null){
				server = connectToServer();
			}
			OneNPC character = new OneNPC();			
			WrappedHeld held = server.getHeld(heldenID);			
			//name
			character.setName(held.getName());			
			//attributes
			character.setAttributeMap(importAttributes(character,held));
			//sfs
			character.setSFs(importSFs(held));
			//talents
			character.setTalentMap(importTalents(character,held));
			//inventory
			importInventory(character,held);
			
			return character;
		} catch (Exception e) {
			
			throw new CharacterImportException(e);
		}	
	}

	private HashMap<String, OneAttribute> importAttributes(OneNPC character, WrappedHeld held) {
		HashMap<String, OneAttribute> resultMap = new HashMap<String, OneAttribute>();
		
		WrappedEigenschaften eigenschaften = held.getEigenschaften();
		
		String nameAttribute;
		OneAttribute attribute;
		
		nameAttribute = OneAttribute.MU;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);		
		
		nameAttribute = OneAttribute.KL;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.IN;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.CH;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.FF;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.GE;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.KK;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);		
		
		nameAttribute = OneAttribute.KO;
		attribute = importAttribute(character, eigenschaften, nameAttribute);
		resultMap.put(nameAttribute, attribute);	
		
		nameAttribute = OneAttribute.GS;
		attribute = new OneAttribute(character,nameAttribute);
		attribute.setCurrentValue(eigenschaften.getGeschwindigkeit());
		resultMap.put(nameAttribute, attribute);
		
		nameAttribute = OneAttribute.SO;
		attribute = new OneAttribute(character,nameAttribute);
		attribute.setCurrentValue(held.getSozialstatus());
		resultMap.put(nameAttribute, attribute);
		
		System.out.println("Attributes imported");
		
		return resultMap;
	}
	private OneAttribute importAttribute(OneNPC character, WrappedEigenschaften eigenschaften,String nameAttribute ){
		OneAttribute attribute = new OneAttribute(character,nameAttribute);
		attribute.setCurrentValue(eigenschaften.getEigenschaft(nameAttribute));
		attribute.setBonus(eigenschaften.getModifikation(nameAttribute));
		attribute.setStartValue(eigenschaften.getStartwert(nameAttribute));
		System.out.println("Attribute imported: "+attribute+":"+attribute.getCurrentValue());
		return attribute;
	}
	
	private List<SF> importSFs(WrappedHeld held) {
		List<SF> sfs = new ArrayList<SF>();
		WrappedSonderfertigkeiten sonderfertigkeiten = held.getSonderfertigkeiten();
		Iterator<WrappedSonderfertigkeit> iterator = sonderfertigkeiten.iterator();
		while(iterator.hasNext()){
			WrappedSonderfertigkeit sonderfertigkeit = iterator.next();
			String name = sonderfertigkeit.toString();
			String art 	= sonderfertigkeit.getArt();
			SF sf = ModelBase.getInstance().getSF(name);
			if(sf != null){
				sfs.add(sf);
				System.out.println("Sf imported: "+sf);
			}else{
				System.err.println("Sf not found: "+name+"(Art: "+art+")");
			}
		}
		return sfs;
	}
	private HashMap<String, OneTalent> importTalents(OneNPC character,WrappedHeld held) {
		HashMap<String, OneTalent> resultMap = new HashMap<String, OneTalent>();
		WrappedTalente talente = held.getTalente();
		Iterator<WrappedTalent> iterator = talente.iterator();
		while(iterator.hasNext()){
			WrappedTalent talent = iterator.next();
			String name = talent.toString();			
			int value = talent.getWert();
			OneTalent myTalent = ModelBase.getInstance().getTalentForCharacter(character, name, value);
			if (myTalent instanceof WeaponTalent) {
				WeaponTalent weaponTalent = (WeaponTalent) myTalent;
				weaponTalent.setAtDistribution(talent.getAttacke());
				weaponTalent.setPaDistribution(talent.getParade());
			}			
			if(myTalent!=null){
				resultMap.put(myTalent.getName(),myTalent);
				System.out.println("Talent imported: "+myTalent);
			}else{
				System.err.println("Talent not found: "+myTalent);
			}
		}
		return resultMap;
	}
	
	private void importInventory(OneNPC character, WrappedHeld held) {
		List<WrappedGegenstand> gegenstaende = held.getInventar().getSortedGegenstandsListe();
		for(int i = 0;i<gegenstaende.size();i++){
			WrappedGegenstand gegenstand = gegenstaende.get(i);
			String name = gegenstand.getName();
			int anzahl = gegenstaende.get(i).getAnzahl();
			for(int j = 0;j<anzahl;j++){				
				Item item= ModelBase.getInstance().getItemByName(name);
				character.addItem(item);
				System.out.println("Item imported: "+item);
			}
		}
	}
	

	private RmtServer connectToServer() throws MalformedURLException, RemoteException, NotBoundException {
		String serverIP = getPreferenceStore().getString(PreferenceConstants.P_RMIServerIP);
		String serverPort = getPreferenceStore().getString(PreferenceConstants.P_RMIServerPort);
		String serverName = getPreferenceStore().getString(PreferenceConstants.P_RMIServerName);
		
		RmtServer server = (RmtServer) Naming.lookup("rmi://" + serverIP + ":"+serverPort+"/"+ serverName);
		return server;
	}
	
	
	public void openView(){
		try {
			if(getPreferenceStore().getBoolean(PreferenceConstants.P_Launch_Server)){
				//TODO search and launch helden-software in rmi
				//if error -> no opening			
			}			
			PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().showView(ImportRMIView.ID);

		} catch (PartInitException e) {	
		}
	}
	@Override
	public void partActivated(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partBroughtToTop(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partClosed(IWorkbenchPartReference partRef) {		
		if(ImportRMIView.ID.equals(partRef.getId())){
			ImportRMIView newView = (ImportRMIView)partRef.getPart(false);
			view = newView;
			if(view!=null){
				view.deRegisterImportListener(importFunctionality);
				view.deRegisterReloadListener(reloadFunctionality);
			}
		}
	}

	@Override
	public void partDeactivated(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partHidden(IWorkbenchPartReference partRef) {
	}

	@Override
	public void partInputChanged(IWorkbenchPartReference partRef) {		
	}

	@Override
	public void partOpened(IWorkbenchPartReference partRef) {
		if(ImportRMIView.ID.equals(partRef.getId())){
			ImportRMIView newView = (ImportRMIView)partRef.getPart(false);
			//if(view!=null){
				newView.deRegisterImportListener(importFunctionality);
				newView.deRegisterReloadListener(reloadFunctionality);
			//}
			view = newView; 
			//register functionality listeners
			view.registerImportListener(importFunctionality);
			view.registerReloadListener(reloadFunctionality);
			//set data in view 
			try {
				view.fillCharacters(getHelden());
			} catch (RemoteException e) {
				e.printStackTrace();
			}			
		}
	}

	@Override
	public void partVisible(IWorkbenchPartReference partRef) {		
	}
	
	private class ImportFunctionality implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			//import the character
			CharacterDescription description = view.getSelectedCharacterDescription();
			String id = description.getId();
			try {
				System.out.println("Trying import of character with id: "+id);
				OneNPC character = importCharacter(id);
				Model.getInstance().addPossibleCharacter(character);
				System.out.println("Imported character: "+character);	
				//notify import complete
				ActionEvent event = new ActionEvent(Activator.this, ActionEvent.ACTION_PERFORMED, "ImportComplete:"+e.getActionCommand());
				for (ActionListener listener : importCompleteListeners) {
					listener.actionPerformed(event);
				}
			} catch (CharacterImportException exc) {
				//import not successfull
				System.out.println("Import not possible: "+exc);	
			}
		}		
	}
	
	private class ReloadFunctionality implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			//reload from helden software
			if(view != null){
				try {
					view.fillCharacters(getHelden());
				} catch (RemoteException e1) {					
				}
			}
		}		
	}
	
	private List<ActionListener> importCompleteListeners = new ArrayList<ActionListener>();
	public boolean registerImportCompleteListener(ActionListener listener){
		return importCompleteListeners.add(listener);
	}
	public boolean deRegisterImportCompleteListener(ActionListener listener){
		return importCompleteListeners.remove(listener);
	}
	
}
